﻿using System;

namespace Interactive.Utility.Collections {
    /// <summary>
    /// 可回收的容器中的容器
    /// </summary>
    /// <typeparam name="K"></typeparam>
    /// <typeparam name="V"></typeparam>
    public class RecycleDics<K, V> {
        private readonly int BucketCount;
        private readonly RecycleDic<K, V>[] Caches;


        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="bucketCount">多少桶</param>
        /// <param name="capacity">容量</param>
        /// <param name="defaultFunc">获取的方法</param>
        /// <param name="defaultBusyValue">标识繁忙的值</param>
        /// <param name="waitMillseconds">等待时间,默认50毫秒</param>
        /// <param name="isLru">是否是LRU算法,默认LFU</param>
        public RecycleDics(int bucketCount, int capacity, Func<K, V> defaultFunc, V defaultBusyValue, 
                           int waitMillseconds,
                           bool isLru){
            BucketCount = bucketCount;

            Caches = new RecycleDic<K, V>[BucketCount];
            for (int i = 0; i < BucketCount; i++){
                Caches[i] = new RecycleDic<K, V>(capacity, defaultFunc, defaultBusyValue,  waitMillseconds,
                                                 isLru);
            }
        }


        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="bucketCount">多少桶</param>
        /// <param name="capacity">容量</param>
        /// <param name="defaultFunc">获取的方法</param>
        /// <param name="defaultBusyValue">标识繁忙的值</param>
        public RecycleDics(int bucketCount, int capacity, Func<K, V> defaultFunc, V defaultBusyValue)
            : this(bucketCount, capacity, defaultFunc, defaultBusyValue,  50, false) {}


        public V this[K key]{
            get { return GetCache(key)[key]; }
            set { GetCache(key)[key] = value; }
        }


        private RecycleDic<K, V> GetCache(K key){
            return Caches[Math.Abs(key.GetHashCode() % BucketCount)];
        }

        /// <summary>
        /// 刷新缓存
        /// </summary>
        /// <param name="key">键</param>
        public void EnforceRefresh(K key){
            GetCache(key).EnforceRefresh(key);
        }

        /// <summary>
        /// 刷新缓存,用默认值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="defaultValue">默认值</param>
        public void EnforceRefresh(K key, V defaultValue){
            GetCache(key).EnforceRefresh(key, defaultValue);
        }

        /// <summary>
        /// 获取值
        /// </summary>
        /// <param name="key">键</param>
        /// <returns>值</returns>
        public V GetVaule(K key){
            return GetCache(key).GetValue(key);
        }

        /// <summary>
        /// 获取值,如果isMust=Ture,代表一定要获取到值,当不存在的时候
        /// 重新建立该项
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="isMust">是否一定要获取到值,true代表是,反之</param>
        /// <returns>值</returns>
        public V GetVaule(K key, bool isMust){
            return GetCache(key).GetValue(key, isMust);
        }

        /// <summary>
        /// 添加一个键,值对,当存在该键时会报错
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="userDynamic">值</param>
        /// <exception cref="ArgumentException">当键存在时会抛出该异常</exception>
        public void Add(K key, V userDynamic){
            GetCache(key).Add(key, userDynamic);
        }

        /// <summary>
        /// 尝试获取
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="userDynamic">值</param>
        /// <returns>是否有</returns>
        public bool TryGetValue(K key, out V userDynamic){
            return GetCache(key).TryGetValue(key, out userDynamic);
        }

         /// <summary>
        /// 是否存在
        /// </summary>
        /// <param name="key">键</param>
        /// <returns>结果</returns>
        public bool ContainsKey(K key){
            return GetCache(key).ContainsKey(key);
        }

        /// <summary>
        /// 移除
        /// </summary>
        /// <param name="key">键</param>
        /// <returns>是否成功</returns>
        public bool Remove(K key){
            return GetCache(key).Remove(key);
        }
    }
}